#ifndef LOMINSTANCEMANAGERHH
#define LOMINSTANCEMANAGERHH
#include "lom-typedefs.hh"
#include "lom-events.hh"

namespace lom
{
    class LomRoot;
    class LomInstance;
    
    /**
       The instance manager supports adding/removing references as well
       as creating reserved handle values.  Reserved handle values
       are useful in the case where an object A has a reference to
       object B.  You send over a description of object A but you
       get a problem because object B doesn't exist yet.  Thus the
       system needs to be able to reserve a handle value for object
       B and add references to it before object B actually exists in order
       to fully and correctly create object A.
     */
    class ILomInstanceManager
    {
    public:
	virtual ~ILomInstanceManager(){}
	
	virtual LomRoot* getRoot( THandle handle, bool throwFail = true ) = 0;

	/// Calls getRoot and then attempts a dynamic cast.
	virtual LomInstance* getInstance( THandle handle, bool throwFail = true) = 0;
	
	virtual void reference( THandle handle, bool errorIfNotExist = true ) = 0;
	virtual void dereference( THandle handle ) = 0;

	/**
	   Register a new object.  IF this value is zero, then a new
	   handle value is allocated for the object.  Else the
	   reserved handle value is used.
	 */
	virtual THandle doregister( LomRoot* item, THandle reservedHandle = 0 ) = 0;
	virtual void deregister( THandle handle ) = 0;
	
	/**
	   Reserve a new handle value.  This allows reference and
	   dereference calls to work on the reserved value.  IF the
	   object is instantiated, the reserved handle is removed from
	   the reserved-handle list and the reference counts are
	   transferred to the existing object.
	*/
	virtual THandle reserveHandle() = 0;

	virtual const THandleRootMap& getHandleToRoots() = 0;
    };

    class LomInstanceManager : public EventSender, public ILomInstanceManager
    {
	THandle curHandle;
	THandleRootMap handleToRoots;
	THandleUInt32Map reservedHandles;
    
    public:
	LomInstanceManager();
	~LomInstanceManager();
	virtual LomRoot* getRoot( THandle handle, bool throwFail = true );
	/**
	   By contract, if reserved handle isn't zero and there isn't an error
	   the return value should be reservedHandle.
	 */
	virtual LomInstance* getInstance( THandle handle, bool throwFail = true);
	virtual THandle doregister( LomRoot* item, THandle reservedHandle = 0 );
	virtual void deregister( THandle handle );
	virtual const THandleRootMap& getHandleToRoots();
	virtual void reference( THandle handle, bool errorIfNotExist = true );
	virtual void dereference( THandle handle );
	virtual THandle reserveHandle();
	
	//deletes all instances, and clears curHandle and handleToRoots
	virtual void reset();
	
    private:
	void internalReset();
    };
}
#endif
